home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Night Owl 6
/
Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso
/
001a
/
b50menu.zip
/
B50MENU.C
next >
Wrap
C/C++ Source or Header
|
1991-08-08
|
9KB
|
272 lines
// B50MENU.C: <ALT> HOT-KEY MENU FOR BOYAN VERSION 5.0
//
// Written in Microsoft C 6.00a
//
// This program will load and execute BOYAN.COM, and it must be located
// in the same directory. (All command line arguments are passed.) A
// Keyboard BIOS request interrupt handler is installed that pops-up a
// help menu when the <Alt> key is pressed at the main terminal screen.
char banner[] =
"B50BENU Version 1.0 Copyright 1991 John Navas II, All Rights Reserved\n\n";
#include <ctype.h>
#include <dos.h>
#include <fcntl.h>
#include <io.h>
#include <process.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define VIDBIOS (0x10) // Video BIOS interrupt
#define GETSHADBUF (0xFE) // Get Video Shadow Buffer service
#define KEYBIOS (0x16) // Keyboard BIOS interrupt
#define KEYREAD (0) // Read Key service
#define KEYSTATUS (1) // Keyboard buffer status service
#define MONOMODE (7) // Monochrome adapter video mode
#define MONOBUF (0xB000) // Monochrome video buffer segment
#define COLORBUF (0xB800) // Color video buffer segment
// These are the two possible values for Boyan's Stack Pointer when B50MENU
// traps a Keyboard BIOS interrupt from Boyan's main terminal screen. (The
// stack pointer is different on other screens.)
#define B50SP1 (0xFFCA)
#define B50SP2 (0xFFD9)
typedef enum { FALSE = 0, TRUE = 1 } BOOL;
typedef unsigned char BYTE;
typedef unsigned short WORD;
#pragma pack(1)
// layout of character and attribute in the video buffer
typedef union { WORD ca; struct { BYTE ch, at; }; } CHAT;
typedef struct { CHAT chat[80]; } VIDLINE; // video buffer display line
#pragma pack()
_segment VidSeg = 0; // segment for video display buffer
VIDLINE VidSave; // save Boyan's status line here
VIDLINE VidMenu; // build pop-up menu here
BOOL MenuOn = FALSE; // has menu been popped up?
// BIOS DATA AREA:
#define KEYBDCNTL() (*(const volatile WORD far*)0x400017) // Key states
#define ALTPRESSED() ((8 & KEYBDCNTL()) != 0) // <Alt> key pressed
#define VIDEOMODE() (*(const BYTE far*)0x400049) // BIOS video mode
#define VIDEOROWS() (*(const BYTE far*)0x400084) // screen rows - 1
static char boyancnf[] = "BOYAN.CNF"; // name of Boyan's CoNFiguration file
#define NORMOFFSET (4) // offset to Help normal color
BYTE normclr = 0x07; // help normal color default
#define HIGHOFFSET (0x322) // offset to Help highlight color
BYTE highclr = 0x0F; // help highlight color default
static char b50menucnf[] = "B50MENU.CNF"; // name of my CoNFig file
static char boyancom[] = "BOYAN.COM"; // name of Boyan executable
char path[_MAX_PATH]; // build file path names here
char menu[] = // default pop-up menu text
"Act Bep Cfg Dial Echo File Hang Jmp Mac Log New Par Que Run Sav Trn Vu Wp eX Zap";
typedef void (_interrupt _far INTHAND)(void); // interrupt service routine
INTHAND _far *OldKeyReq = 0; // save old key request int here
// BUILD MENU VIDEO LINE FROM TEXT AND ATTRIBUTES:
#pragma check_stack(off)
void
SetupMenu(void)
{
register int i;
for (i = 0; i < sizeof(menu); ++i) { // entire line
VidMenu.chat[i].ch = menu[i]; // text character
VidMenu.chat[i].at = // attribute depends on case
(BYTE)(isupper(menu[i]) ? highclr : normclr);
}
}
#pragma check_stack()
// CHECK TO SEE IF BOYAN HAS CORRUPTED THE POP-UP MENU (E.G. WITH THE TIMER);
// IF SO, COPY THE CHANGES TO THE SAVE BUFFER AND OPTIONALLY FIX THE MENU:
#pragma check_stack(off)
void
_fastcall UpdateVidSave(
VIDLINE _based(VidSeg) *line, // video buffer display line
BOOL fix // fix the menu if TRUE
)
{
int i;
for (i = 0; i < sizeof(menu); ++i) { // entire menu line
if (VidMenu.chat[i].ca != line->chat[i].ca) { // if corrupted...
VidSave.chat[i] = line->chat[i]; // save the changes
if (fix) // and if desired...
line->chat[i] = VidMenu.chat[i]; // fix the menu
}
}
}
#pragma check_stack()
// THIS TRAP ROUTINE INTERCEPTS ALL KEYBOARD BIOS REQUESTS, AND CALLS THE
// ORIGINAL HANDLER AS APPROPRIATE; ITS PRIMARY PURPOSE IS TO POP-UP THE
// MENU WHEN <ALT> IS FIRST PRESSED, AND REMOVE IT WHEN EITHER (1) <ALT>
// IS RELEASED OR (2) ANY REGULAR KEY IS PRESSED:
#if !defined(QCC_)
#pragma intrinsic(_enable)
#endif
#pragma check_stack(off)
void
_interrupt _far KeyReqTrap(
unsigned _es, unsigned _ds, // caller's registers
unsigned _di, unsigned _si,
unsigned _bp, unsigned _sp,
unsigned _bx, unsigned _dx,
unsigned _cx, unsigned _ax,
unsigned _ip, unsigned _cs,
unsigned flags )
{
BYTE opcode; // save AH function code here
static BOOL oldalt, newalt; // last and current <Alt> key status
VIDLINE _based(VidSeg) *line; // last line of video buffer
_enable(); // allow interrupts
opcode = (BYTE)(_ax >> 8); // save AH function code
switch (opcode) {
case KEYREAD: // we only care about these two
case KEYSTATUS: // function codes
break;
default:
_chain_intr(OldKeyReq); // otherwise go to original handler
} // for safety (won't return)
_asm mov ax,_ax // ensure AX valid
OldKeyReq(); // call original handler (returns)
_asm pushf // save flags for caller
_asm pop flags
_asm mov _ax,ax // and save AX for caller
if (0 == VidSeg) { // if not initialized yet...
if (MONOMODE == VIDEOMODE()) { // pick proper video segment
VidSeg = MONOBUF;
}
else {
VidSeg = COLORBUF;
}
_asm { // get video shadow buffer if
mov es,VidSeg // under TopView or DESQview
xor di,di
mov ah,GETSHADBUF
int VIDBIOS
mov VidSeg,es
}
SetupMenu(); // initialize menu video buffer
}
line = 0; // point to last line in video
line += VIDEOROWS(); // display buffer
oldalt = newalt; // last <Alt> key state
newalt = ALTPRESSED(); // current <Alt> key state
// conditions under which menu is NOT displayed:
if (KEYREAD == opcode || !newalt || (B50SP1 != _sp && B50SP2 != _sp)) {
if (MenuOn) { // if menu popped up...
UpdateVidSave(line, FALSE); // save any last changes
*line = VidSave; // and remove menu
MenuOn = FALSE;
}
}
else { // otherwise pop-up menu
if (!MenuOn) { // if not yet popped-up...
if (!oldalt) { // only pop-up if <Alt> just pressed
VidSave = *line; // save Boyan display
*line = VidMenu; // pop-up menu
MenuOn = TRUE;
}
}
else // already popped-up
UpdateVidSave(line, TRUE); // pick up any changes by Boyan
}
}
#pragma check_stack()
// MAKE FULL PATH NAME, TAKING THE DRIVE AND DIRECTORY FROM THE 2ND ARGUMENT
// AND THE FILENAME AND EXTENTION FROM THE 3RD ARGUMENT:
char* // returns path
MakePath(
char *path, // build path here
const char *drdir, // pick up drive and directory
const char *filext // pick up filename and extention
)
{
char drive[_MAX_DRIVE]; // work areas and pointer
char dir[_MAX_DIR];
char fname[_MAX_FNAME];
char ext[_MAX_EXT];
_splitpath(drdir, drive, dir, NULL, NULL);
_splitpath(filext, NULL, NULL, fname, ext);
_makepath(path, drive, dir, fname, ext);
return path;
}
// GET HELP COLORS FROM BOYAN'S CONFIGURATION FILE (IF IT EXISTS):
void
GetColors(char *path)
{
int cnf = open(path, O_BINARY | O_RDONLY);
if (-1 == cnf)
perror(path);
else {
lseek(cnf, NORMOFFSET, SEEK_SET); // Help normal color
read(cnf, &normclr, sizeof(normclr));
lseek(cnf, HIGHOFFSET, SEEK_SET); // Help highlight color
read(cnf, &highclr, sizeof(highclr));
close(cnf);
}
}
// IF MY CONFIGURATION FILE EXISTS, READ MENU TEXT LINE:
void
GetText(char *path)
{
int cnf = open(path, O_TEXT | O_RDONLY);
if (-1 != cnf) {
read(cnf, menu, sizeof(menu));
close(cnf);
}
}
// RESTORE ORIGINAL KEYBOARD REQUEST BIOS VECTOR:
void
cleanup(void)
{
if (OldKeyReq)
_dos_setvect(KEYBIOS, OldKeyReq);
}
int
main(int ac, char *av[])
{
int ret;
MakePath(path, av[0], boyancnf); // Get colors
GetColors(path);
MakePath(path, av[0], b50menucnf); // Get menu text
GetText(path);
MakePath(path, av[0], boyancom); // Boyan's executable pathname
atexit(cleanup); // ensure BIOS vector restored
OldKeyReq = _dos_getvect(KEYBIOS); // get original key request vector
_dos_setvect(KEYBIOS, KeyReqTrap); // install my intercept routine
ret = spawnv(P_WAIT, path, av + 1); // run Boyan as a child process
if (-1 == ret)
perror(path);
return ret; // return Boyan's return code
}
// B5MENU.C